#pragma once

#include <sstream>
#include <string>
#include <spdlog/spdlog.h>

inline std::string int2str(int num)
{
    std::ostringstream oss;
    oss << num;
    return oss.str();
}

class LogWrapper
{
public:
    static LogWrapper*getInstance();
    virtual ~LogWrapper();
    template<typename... Args>
    void fatal(const char *msg, const Args &... args) {
        mLogger->critical(msg, args...);
    }
    template<typename... Args>
    void error(const char *msg, const Args &... args) {
        mLogger->error(msg, args...);
    }
    template<typename... Args>
    void info(const Args &... args) {
        mLogger->info(args...);
    }
    template<typename... Args>
    void debug(const char *msg, const Args &... args) {
        mLogger->debug(msg, args...);
    }
    template<typename... Args>
    void trace(const Args &... args) {
        mLogger->trace(args...);
    }
    template<typename... Args>
    void warn(const char *msg, const Args &... args) {
        mLogger->warn(msg, args...);
    }
private:
    LogWrapper();
    void outputLog(const char *fmt, ...);
private:
    std::shared_ptr<spdlog::logger> mLogger;
    static LogWrapper *mInstance;
};

#ifdef _LOGGER_INIT_
LogWrapper *pLog = LogWrapper::getInstance();
#else
extern LogWrapper *pLog;
#endif

#define postfix(msg) std::string(msg).append("(").append(__FILE__)\
			   .append("-").append(__func__)\
			   .append("-").append(int2str(__LINE__))\
			   .append(")").c_str()

#define LOG_FATAL(msg,...) pLog->fatal(postfix(msg),__VA_ARGS__)
#define LOG_ERROR(msg,...) pLog->error(postfix(msg), __VA_ARGS__)
#define LOG_INFO(msg, ...)  pLog->info(postfix(msg), __VA_ARGS__)
#define LOG_DEBUG(msg,...) pLog->debug(postfix(msg), __VA_ARGS__)
#define LOG_TRACE(msg,...) pLog->trace(postfix(msg), __VA_ARGS__)
#define LOG_WARN(msg,...) pLog->warn(postfix(msg), __VA_ARGS__)